#!/usr/bin/env python3
import subprocess
import sys
import argparse
import logging
import tempfile
from pathlib import Path
from typing import Dict, List


EXIT_PAMAS = 11
EXIT_WITH_FAILS = 12

SUCCEEDED_BUILD = []
FAILED_BUILD = []

logger = logging.getLogger('BingoBuild')
logger.setLevel(logging.INFO)
formatter = logging.Formatter('[%(name)s] - [%(levelname)s] - %(message)s')
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)


def _run_command(cmd: str, cwd: str = None) -> bool:
    logger.info(f"Running: {cmd}")
    try:
        proc = subprocess.Popen(
            cmd,
            cwd=cwd,
            shell=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            text=True,
            bufsize=1,
            universal_newlines=True,
            encoding="utf-8"
        )

        while True:
            output = proc.stdout.readline().strip()
            if output == "" and proc.poll() is not None:
                break
            if output:
                logger.info(output)

        exit_code = proc.poll()
        if exit_code != 0:
            logger.info(f"Command failed with code {exit_code}")
            return False
        return True
    except Exception as e:
        logger.exception("Command failed", extra_data={"error": str(e), "status": "error"})
        return False


def _process_repos(repos: List[str]) -> Dict[str, str]:
    global SUCCEEDED_BUILD
    global FAILED_BUILD

    with tempfile.TemporaryDirectory(prefix="repo_clone_") as temp_dir:
        for repo in repos:
            if "=" not in repo:
                logger.error(f"Invalid repository format: {repo}")
                logger.error(f"Use name=url format")
                sys.exit(EXIT_PAMAS)

            name, url = repo.split("=", 1)
            name = name.strip()
            url = url.strip()

            if not name or not url:
                logger.error(f"Invalid repository format: {repo}")
                sys.exit(EXIT_PAMAS)

            logger.info(f"Cloning {name}...")
            repo_path = Path(temp_dir) / name
            if not _run_command(f"git clone {url} {repo_path}"):
                logger.error(f"Failed to clone: {name}!")
                FAILED_BUILD.append(name)
                continue
            
            _test_build(name, repo_path)


def _test_build(comp_name: str, comp_path: Path):
    global SUCCEEDED_BUILD
    global FAILED_BUILD            

    logger.info(f"Build {comp_name}")
    if not comp_path.expanduser().exists():
        logger.error(f"Path not found: {comp_path}")
        FAILED_BUILD.append(comp_name)
        return

    if not _run_command("bingo build", cwd=comp_path.expanduser()):
        FAILED_BUILD.append(comp_name)
    else:
        SUCCEEDED_BUILD.append(comp_name)


def main(args: argparse.Namespace):
    _test_build("manifest", args.manifest_path)
    _process_repos(args.repos)

    logger.info(f"============== SUMMARY ============")
    if SUCCEEDED_BUILD:
        logger.info(f"SUCCESS:")
        for name in SUCCEEDED_BUILD:
            logger.info(f"\t{name}")
    if FAILED_BUILD:
        logger.error(f"FAIL:")
        for name in FAILED_BUILD:
            logger.error(f"\t{name}")
        sys.exit(EXIT_WITH_FAILS)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("repos", nargs="+", help="Repos in name=url format")
    parser.add_argument("-m", "--manifest-path", type=Path)

    args = parser.parse_args()

    main(args)

